package com.hjh.netty.elect.demo4;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hjh.netty.elect.config.BeanCopierUtils;
import com.hjh.netty.elect.config.SpringUtils;
import com.hjh.netty.elect.util.CheckSumUtils;
import com.hjh.netty.elect.util.NumberDataConvertUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 可用网络调试助手、Modbus Poll进行调试
* */
@Slf4j
@Component
public class Pmc350DecoderHandler extends SimpleChannelInboundHandler<Pmc350ProtocolModel> {
    @Autowired
    private Iot350DataParseService iot350DataParseService;
    
//    @Autowired
//    private MsgProducer msgProducer;
//
//    @Autowired
//    private DeviceInfoService deviceInfoService;

    /**
     * 读取客户端PMC350电表传过来的数据
     * 解析后转发到mq，让link模块进行入库
     * Object msg
     * */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Pmc350ProtocolModel msg) throws Exception {
    	try {
    		 if (msg == null) {
                 log.warn("[PMC-350]-["+ctx.channel().remoteAddress()+"]-接收到客户端上传数据为空");
                 return;
             }
            if(iot350DataParseService == null) {
            	iot350DataParseService = SpringUtils.getBean("iot350DataParseService");
            }
            //数据解析
            log.info("接收到的数据：" + JSONObject.toJSONString(msg.getUplaodData()));
            BaseAutoUploadDatas<?> result = iot350DataParseService.analysisPmc350DataByDecoder(ctx, msg);
            log.info("解析完的数据：" + JSONObject.toJSONString(result));
            if(result == null) {
            	log.error("解析PMC-350上传数据为空！");
            	return;
            }
            //心跳包
            if("000".equals(result.getPacketFlag())) {
//            	if(deviceInfoService == null) {
//            		deviceInfoService = SpringUtils.getBean("deviceInfoService");
//                }
            	//判断发送设备在线离线
//            	deviceInfoService.doDeviceOnline(result);
            	//将设备对应的通道缓存起来
            	String deviceId = result.getDeviceIdCode();
            	TcpServer.putDeviceChannelId(deviceId, ctx.channel().id());
            }
            //Modbus 回复帧
            else if("001".equals(result.getPacketFlag())) {
            	log.info("收到Modbus RTU回复帧：" + JSONObject.toJSONString(result));
            	//发送MQ消息，处理遥控设置返回的消息
            	//sendModbusResponseMqMessage(result);
            }
            //终端的主动上送报文(定时数据上报)，不需要主站回复
            else if("010".equals(result.getPacketFlag())) {
            	//发送MQ消息，link模块处理数据入库
//                sendMqMessage(result);
            }
            //终端的主动上送报文，需要主站回复 ACK
            else if("011".equals(result.getPacketFlag())) {
            	//封装应答
            	BeanCopierUtils.copyProperties(msg, result);
            	PayLoadDatas payLaodObj = (PayLoadDatas) result.getPayLaod();
            	//事件上送，做电表DI1,DI2,DI3,DO1,DO2状态的处理
            	if("010".equals(payLaodObj.getUpDataMainType())) {
        			log.info("["+msg.getDeviceIdCode()+"]电表上传事件：" + JSONObject.toJSONString(payLaodObj));
        			//解析时间信息
        			SoeDatas soeDatas = (SoeDatas) payLaodObj.getUpLoadData();
        			JSONArray uploadDatas = processEventData(soeDatas);
        			//发送mq，记录事件信息
//        			sendEventMqMessage(result, uploadDatas);
            	}
                Pmc350ProtocolModel replyMessage = getAckMessage(result);
                //log.info("回复消息：{}", JSONObject.toJSONString(replyMessage));
         		replyMessage(ctx.channel(), replyMessage);
            }
           
    	}catch(Exception e) {
    		log.error("解析出错，" + e.getMessage());
    	}
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (cause instanceof Exception) {
            log.error("netty-->异常捕获:{}" + cause);
            //cause.printStackTrace();
        }
    }
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        TcpServer.deviceAdd(ctx.channel());
        //这里要根据设备标识将设备标识存入map
        //TcpServer.putDeviceChannelId(clientId, channelId);
        log.info("netty-->TCP客户端服务上线：" + channel.remoteAddress());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        try {
            Channel channel = ctx.channel();
            TcpServer.deviceRemove(ctx.channel());
            log.info("netty-->TCP客户端服务下线：" + channel.remoteAddress());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //log.info("接收到客户端信息完成");
        ctx.flush();
    }
    
    /**
     * 处理事件上送信息，主要对电表DI1,DI2,DI3,DO1,DO2状态的处理
     * @param soeDatas
     */
    private JSONArray processEventData(SoeDatas soeDatas) {
    	JSONArray jsonArray = new JSONArray();
    	List<SoeLog> soeLogList = soeDatas.getSoeLogList();
    	if(CollUtil.isEmpty(soeLogList)) {
    		return jsonArray;
    	}
    	for(SoeLog soeLog : soeLogList) {
    		JSONObject json = new JSONObject();
    		//上传日期
            String dateTime = soeLog.getYear() + "-" + convertDateTime(soeLog.getMonth()) + "-"
            			+ convertDateTime(soeLog.getDay()) + " " + convertDateTime(soeLog.getHour()) + ":"
            			+ convertDateTime(soeLog.getMinute()) + ":" + convertDateTime(soeLog.getSecond());
            			//+ "." + soeLog.getMillisecond();
            //ts
            long ts = DateUtils.converDate2TimeStamp(dateTime);
            json.put("ts", ts);
            json.put("tsFormat", dateTime);
    		//大类1，DI变位事件 
    		if(soeLog.getHigthType() == 1) {
    			//小类1，DI1
        		if(soeLog.getLowType() == 1) {
        			json.put("di1", soeLog.getActionInfo());
        		}
        		//小类2，DI2
        		else if(soeLog.getLowType() == 2) {
        			json.put("di2", soeLog.getActionInfo());
        		}
        		//小类3，DI3
        		else if(soeLog.getLowType() == 3) {
        			json.put("di3", soeLog.getActionInfo());
        		}
    		}
    		//大类2，DO动作事件 
    		else if(soeLog.getHigthType() == 1) {
    			//小类1，D01
    			if(soeLog.getLowType() == 1) {
    				json.put("do1", soeLog.getActionInfo());
        		}
        		//小类2，D02
        		else if(soeLog.getLowType() == 2) {
        			json.put("do2", soeLog.getActionInfo());
        		}
    		}
    		jsonArray.add(json);
    	}
    	return jsonArray;
    }
    
    /**
     * 发送modbus响应返回的数据
     * @param result
     */
//    private void sendModbusResponseMqMessage(BaseAutoUploadDatas<?> result) {
//    	ModbusPayLoadDatas modbusPayLoadDatas = (ModbusPayLoadDatas) result.getPayLaod();
//        String topic = "/tcp/modbus/"+result.getDeviceIdCode()+"/response";
//        //消息体
//        SmartGateReceiverDto sendMsg = SmartGateReceiverDto.builder()
//        		.topic(topic)
//        		.qos("1")
//        		.msg(JSONObject.toJSONString(modbusPayLoadDatas))
//        		.build();
//        //发送MQ消息
////        if(msgProducer == null) {
////        	msgProducer = SpringUtils.getBean("msgProducer");
////        }
////        msgProducer.senJsonObject(ConsumerTopicConstant.THINGLINKS_LINK_MQTT_MSG, JSONObject.toJSONString(sendMsg));
//    }
    
    /**
     * 发送电表信息到MQ
     * @param result
     */
//    private void sendMqMessage(BaseAutoUploadDatas<?> result) {
//    	PayLoadDatas payLoadDatas = (PayLoadDatas) result.getPayLaod();
//    	//日期
//        String dateTime = payLoadDatas.getYear() + "-" + convertDateTime(payLoadDatas.getMonth()) + "-"
//        			+ convertDateTime(payLoadDatas.getDay()) + " " + convertDateTime(payLoadDatas.getHour()) + ":"
//        			+ convertDateTime(payLoadDatas.getMinute()) + ":" + convertDateTime(payLoadDatas.getSecond());
//        //解析的电表数据
//        JSONObject uploadDataJson = JSONObject.parseObject(JSONObject.toJSONString(payLoadDatas.getUpLoadData()));
//        //设备信息
//        DeviceRtdMongo deviceRtdMongo = DeviceRtdMongo.builder()
//                ._id(result.getDeviceIdCode())
//                //.dataType(convertDataType(payLoadDatas))
//                .dataType(2) //2：电表TCP上传
//                .ts(DateUtils.converDate2TimeStamp(dateTime))
//                .tsFormat(dateTime)
//                .deviceIdentification(result.getDeviceIdCode())
//                .lastUpdateTime(new Date())
//                .data(uploadDataJson)
//                .build();
//        //topic
//        String topic = "/tcp/pmc/"+result.getDeviceIdCode()+"/rtg";
//        //消息体
//        SmartGateReceiverDto sendMsg = SmartGateReceiverDto.builder()
//        		.tcpUploadType(convertDataType(payLoadDatas)) //TCP上传类型
//        		.topic(topic)
//        		.qos("1")
//        		.msg(JSONObject.toJSONString(deviceRtdMongo))
//        		.build();
//        //发送MQ消息
////        if(msgProducer == null) {
////        	msgProducer = SpringUtils.getBean("msgProducer");
////        }
////        msgProducer.senJsonObject(ConsumerTopicConstant.THINGLINKS_LINK_MQTT_MSG, JSONObject.toJSONString(sendMsg));
//    }
    
    /**
     * 发送电表的事件信息
     * @param result
     */
//    private void sendEventMqMessage(BaseAutoUploadDatas<?> result, JSONArray uploadDatas) {
//    	PayLoadDatas payLoadDatas = (PayLoadDatas) result.getPayLaod();
//    	SoeDatas soeDatas = (SoeDatas) payLoadDatas.getUpLoadData();
//    	//日期
//        String dateTime = payLoadDatas.getYear() + "-" + convertDateTime(payLoadDatas.getMonth()) + "-"
//        			+ convertDateTime(payLoadDatas.getDay()) + " " + convertDateTime(payLoadDatas.getHour()) + ":"
//        			+ convertDateTime(payLoadDatas.getMinute()) + ":" + convertDateTime(payLoadDatas.getSecond());
//        //事件信息
//        DeviceSoeMongo deviceSoeMongo = DeviceSoeMongo.builder()
//        		._id(null)
//        		.ts(DateUtils.converDate2TimeStamp(dateTime))
//        		.tsFormat(dateTime)
//        		.deviceIdentification(result.getDeviceIdCode())
//        		.manufacturerType(0)
//        		.uploadData(soeDatas.getUploadSoeData()) //上传的tcp 16j进制字符串
//        		.data(uploadDatas) //解析完全的数据
//        		.build();
//
//        //topic
//        String topic = "/tcp/pmc/"+result.getDeviceIdCode()+"/soe";
//        //消息体
//        SmartGateReceiverDto sendMsg = SmartGateReceiverDto.builder()
//        		.tcpUploadType(0) //TCP上传类型
//        		.topic(topic)
//        		.qos("1")
//        		.msg(JSONObject.toJSONString(deviceSoeMongo))
//        		.build();
//        //发送MQ消息
//        if(msgProducer == null) {
//        	msgProducer = SpringUtils.getBean("msgProducer");
//        }
//        msgProducer.senJsonObject(ConsumerTopicConstant.THINGLINKS_LINK_MQTT_MSG, JSONObject.toJSONString(sendMsg));
//    }
    
    
    /**
     * 回复消息
     * @param message
     */
    public void replyMessage(Channel channel, Pmc350ProtocolModel message){
        channel.writeAndFlush(message);
    }
    
    
    /**
     * 封装应答报文
     * @param uploadData 上传的数据
     * @return
     */
    public Pmc350ProtocolModel getAckMessage(BaseAutoUploadDatas<?> uploadData) {
    	PayLoadDatas payLoadDatas = (PayLoadDatas) uploadData.getPayLaod();
    	/** 封装应答payload* */
    	StringBuilder payload = new StringBuilder();
    	//上送类型/子类型 1 字节 与终端上送数据保持一致
    	payload.append(payLoadDatas.getMainAndSubType());
    	//分组号及子类型版本号 1 字节 与终端上送数据保持一致
    	payload.append(payLoadDatas.getUpGrpNumAndDataTypeVer());
    	//数据包标识 1 字节 与终端上送数据保持一致
    	payload.append(payLoadDatas.getPackageId());
    	//子设备标识符 2 字节 预留，固定为 0
    	payload.append("0000");
    	
    	/** 封装应答报文 **/
    	Pmc350ProtocolModel ack = new Pmc350ProtocolModel();
    	//固定F9
    	ack.setPacketHeader("F9");
    	//包标识, 101：表示主站回复给终端的 ACK 报文， 00000101
    	ack.setPacketFlag("05");
    	//设备识别码长度(这里要减1)
    	ack.setDeviceIdCodeLength(uploadData.getDeviceIdCodeLength() - 1);
    	//设备识别码(注册包)
    	ack.setDeviceIdCode(uploadData.getDeviceIdCode());
    	//PayLoad 部分总长度
    	ack.setPayLoadLength(NumberDataConvertUtils.hexString2decimalInt(String.valueOf(payload.length() / 2)));
    	//PayLoad 累加和校验
    	String PayLoadVerifyTotal = CheckSumUtils.doChecksum(payload.toString());
    	ack.setPayLoadVerifyTotal(PayLoadVerifyTotal);
    	//固定F9
    	ack.setPacketHeaderEnd("F9");
    	//PayLoad 部分
    	ack.setPayLoad(payload.toString());
    	
    	return ack;
    }
    
    /**
     * 转换月日时分秒，不够10要在前面补0
     * @param dateItem
     * @return
     */
    private String convertDateTime(String dateItem) {
    	String result = "";
    	int item = Integer.parseInt(dateItem);
    	if(item < 10) {
    		result = "0";
    	}
    	result = result + item;
    	return result;
    }
  
    /**
     * 	上传的数据类型
     * 1：电表TCP上传——实时测量数据（子类1，版本1）
     * 2：电表TCP上传——基本电能数据（子类2，版本0）
     * 3：电表TCP上传——基本谐波及电能质量数据（子类3，版本0）
     * 4：电表TCP上传——需量数据（子类4，版本0）
     * 5：电表TCP上传——自定义测点数据（子类1，版本2）
     * @param payLoadDatas 上传的PayLoad数据
     * @return
     */
    private int convertDataType(PayLoadDatas payLoadDatas) {
    	int dataType = 0;
    	//子类1，版本1：实时测量数据
    	if(payLoadDatas.getUpDataSubType() == 1 && payLoadDatas.getUpDataTypeVer() == 1) {
    		dataType = 1;
    	}
    	else if(payLoadDatas.getUpDataSubType() == 2 && payLoadDatas.getUpDataTypeVer() == 0) {
    		dataType = 2;
    	}
    	else if(payLoadDatas.getUpDataSubType() == 3 && payLoadDatas.getUpDataTypeVer() == 0) {
    		dataType = 3;
    	}
    	else if(payLoadDatas.getUpDataSubType() == 4 && payLoadDatas.getUpDataTypeVer() == 0) {
    		dataType = 4;
    	}
    	else if(payLoadDatas.getUpDataSubType() == 1 && payLoadDatas.getUpDataTypeVer() == 2) {
    		dataType = 5;
    	}
    	return dataType;
    }
    
}
